package com.zbkj.crmeb.order.pprocess;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import com.zbkj.crmeb.chant.request.PurchaseProductRequest;
import com.zbkj.crmeb.merchant.api.request.BuyMemberRequest;
import com.zbkj.crmeb.store.model.StoreOrderInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.constants.WeChatConstants;
import com.crmeb.core.exception.CrmebException;
import com.utils.CrmebUtil;
import com.utils.RestTemplateUtil;
import com.utils.WxPayUtil;
import com.utils.XmlUtil;
import com.zbkj.crmeb.finance.model.UserRecharge;
import com.zbkj.crmeb.front.request.OrderCreateRequest;
import com.zbkj.crmeb.front.response.OrderPayResponse;
import com.zbkj.crmeb.payment.vo.hkwechat.HKPayRefundRequest;
import com.zbkj.crmeb.payment.vo.hkwechat.HKPayRefundResponse;
import com.zbkj.crmeb.payment.vo.hkwechat.HkPayAttachVo;
import com.zbkj.crmeb.payment.vo.hkwechat.HkPayPaymentRequest;
import com.zbkj.crmeb.payment.vo.hkwechat.HkPayPaymentResponse;
import com.zbkj.crmeb.store.model.StoreOrder;
import com.zbkj.crmeb.store.request.StoreOrderRefundRequest;
import com.zbkj.crmeb.system.model.SystemConfig;
import com.zbkj.crmeb.system.service.SystemConfigService;
import com.zbkj.crmeb.user.model.UserToken;
import com.zbkj.crmeb.user.service.UserTokenService;

/**
 * @ClassName: wechat4hkOrderProcess
 * @Description: 微信支付forHK
 */
@Service("wechat4hkOrderProcess")
public class Wechat4HkOrderProcess extends AbstractOrangePayOrderProcess {

    public Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 连接超时 毫秒
     */
    private static final Integer CONNECT_TIME_OUT = 5000;
    /**
     * 响应超时 毫秒
     */
    private static final Integer RESP_TIME_OUT = 30000;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private RestTemplateUtil restTemplateUtil;

    @Autowired
    private UserTokenService userTokenService;

    public OrderPayResponse creatPayOrder(String key, OrderCreateRequest orderRequest, String ip) {
        OrderPayResponse orderPayResponse = new OrderPayResponse();

        StoreOrder storeOrder = super.createOrder(key, orderRequest, ip);
        orderPayResponse.addExtend("orderId",storeOrder.getOrderId());
        // 检查订单状态

        orderPayResponse.setStatus("WECHAT_HK_PAY");
        HkPayPaymentResponse paymentResponse = getHkPayPaymentRequest(storeOrder,ip);
        Map<String,Object> result = new HashMap<>();
        result.put("pay_info",paymentResponse.getPay_info());
        result.put("token_id",paymentResponse.getToken_id());
        result.put("order_id",storeOrder.getOrderId());
        orderPayResponse.setResult(result);
        return orderPayResponse;
    }

    @Override
    public HashMap<String, Object> toPayOrder(StoreOrder order, String ip) {
        //支付调用请求
        HkPayPaymentResponse paymentResponse = getHkPayPaymentRequest(order,ip);
        HashMap<String, Object> resultMap = new HashMap<>();
        Map<String,Object> result = new HashMap<>();
        result.put("pay_info",paymentResponse.getPay_info());
        result.put("token_id",paymentResponse.getToken_id());
        result.put("order_id",order.getOrderId());
        resultMap.put("data", result);
        resultMap.put("result", "SUCCESS");
        resultMap.put("status", "WECHAT_HK_PAY");
        return resultMap;
    }

    private HkPayPaymentResponse getHkPayPaymentRequest(StoreOrder order, String ip){
        try {
            HkPayPaymentRequest paymentRequest = new HkPayPaymentRequest();
            //获取商户号 密钥
            String mchId = getSysConfigValue(WeChatConstants.HK_PAY_MCH_ID,order.getMerId());
            String secretKey = getSysConfigValue(WeChatConstants.HK_PAY_SECRET_KEY,order.getMerId());
            String appId = getSysConfigValue(WeChatConstants.HK_PAY_APPID,order.getMerId());

            paymentRequest.setService(WeChatConstants.HK_PAY_JSPAY_SERVICE);
            paymentRequest.setVersion("2.0");
            paymentRequest.setCharset("UTF-8");
            paymentRequest.setSign_type("MD5");
            paymentRequest.setMch_id(mchId);
            paymentRequest.setIs_raw("1");//是否原生态 值為 1：是；值為 0：否；不傳默認是 0
            paymentRequest.setIs_minipg("1");//是否小程式支付 值為 1，表示小程式支付；不傳或值不為 1， 表示公眾帳號內支付
            paymentRequest.setOut_trade_no(order.getOrderId());
            paymentRequest.setBody("商品描述");
            //用户id 查询openId
            Integer userId = order.getUid();
            LambdaQueryWrapper<UserToken> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserToken::getUid , userId);
            UserToken userToken = userTokenService.getOne(queryWrapper);
            paymentRequest.setSub_openid(userToken.getToken());
            paymentRequest.setSub_appid(appId);
            //TODO 增加用户id等校验
            HkPayAttachVo attachVo = new HkPayAttachVo();
            attachVo.setUserId(userId);
            attachVo.setType("order");
            paymentRequest.setAttach(JSON.toJSONString(attachVo));
            paymentRequest.setTotal_fee(order.getPayPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
            paymentRequest.setMch_create_ip(ip);
            String domain = systemConfigService.getValueByKeyException(WeChatConstants.DOMAIN);
            paymentRequest.setNotify_url(domain + WeChatConstants.PAY_NOTIFY_API_URI_HKPAY);
            paymentRequest.setLimit_credit_pay("0");
//        paymentRequest.setCallback_url("");
//        paymentRequest.setTime_start("");
//        paymentRequest.setTime_expire("");
//        paymentRequest.setGoods_tag("");
            paymentRequest.setNonce_str(getRandomStringByLength(32));
//        paymentRequest.setLimit_credit_pay("0");
            //计算签名
            Map<String, Object> data = CrmebUtil.objectToMap(paymentRequest);
            String sign = WxPayUtil.generateSignature(data, secretKey,"MD5");
            paymentRequest.setSign(sign);
            logger.info("请求香港支付订单参数,param:{} ------- sign:{}", JSONObject.toJSONString(paymentRequest), paymentRequest.getSign());
            String param = XmlUtil.objectToXml(paymentRequest);
            logger.info("请求香港支付订单参数,orderId:{},xml:{}",order.getOrderId(),param);
            String xml = restTemplateUtil.postXml(WeChatConstants.HK_PAY_API_URL, param);
            logger.info("请求香港支付订单参数响应,orderId:{},xml:{}",order.getOrderId(),xml);
            if (StringUtils.isBlank(xml)){
                logger.info("香港支付订单接口调用失败");
                throw new CrmebException("香港支付订单接口调用失败");
            }
            //解析xml
            HashMap<String, Object> map = XmlUtil.xmlToMap(xml);
            HkPayPaymentResponse paymentResponse = CrmebUtil.mapToObj(map, HkPayPaymentResponse.class);
            if (!"0".equals(paymentResponse.getStatus())){
                throw new CrmebException(paymentResponse.getMessage());
            }
            if (!"0".equals(paymentResponse.getResult_code())){
                throw new CrmebException(paymentResponse.getErr_msg());
            }
            return paymentResponse;
        }catch (Exception e){
            e.printStackTrace();
            logger.info("请求香港支付订单异常,Exception:{}",e);
            throw new CrmebException("香港支付接口调用异常");
        }
    }

    @Override
    public boolean refund(StoreOrderRefundRequest request, StoreOrder storeOrder, StoreOrderInfo storeOrderInfo) {
        HKPayRefundRequest refundRequest = getRefundRequestInfo(request, storeOrder);
        logger.info("请求香港支付退款参数,param:{} ------- sign:{}", JSONObject.toJSONString(refundRequest), refundRequest.getSign());
        try {
            String param = XmlUtil.objectToXml(refundRequest);
            logger.info("请求香港支付退款参数,orderId:{},xml:{}",storeOrder.getOrderId(),param);
            String xml = restTemplateUtil.postXml(WeChatConstants.HK_PAY_API_URL, param);
            logger.info("请求香港支付退款返回,orderId:{},xml:{}",storeOrder.getOrderId(),xml);
            if (StringUtils.isBlank(xml)){
                logger.info("退款接口调用失败");
                return false;
            }
            //解析xml
            HashMap<String, Object> map = XmlUtil.xmlToMap(xml);
            HKPayRefundResponse refundResponse = CrmebUtil.mapToObj(map, HKPayRefundResponse.class);
            if (!"0".equals(refundResponse.getStatus())){
                storeOrderStatusService.saveRefund(storeOrderInfo.getOrderId(),storeOrderInfo.getChildOrderNumber(), request.getAmount(), "失败,错误信息:"+ refundResponse.getMessage() +",退款编号:" + refundRequest.getOut_refund_no(),request.getType() == 1);
                throw new CrmebException(refundResponse.getMessage() + "");
            }
            if (!"0".equals(refundResponse.getResult_code())){
                storeOrderStatusService.saveRefund(storeOrderInfo.getOrderId(),storeOrderInfo.getChildOrderNumber(), request.getAmount(), "失败,错误代码:"+ refundResponse.getErr_code()+",退款编号:" + refundRequest.getOut_refund_no(),request.getType() == 1);
                throw new CrmebException(refundResponse.getErr_code() + "");
            }
            return goOnRefund(request, storeOrder,storeOrderInfo);
        } catch (Exception e) {
            logger.info("请求香港支付退款失败e", e);
        }
        return false;
    }

    @Override
    public Object buyMember(BuyMemberRequest request) {
        //支付调用请求
        HkPayPaymentResponse paymentResponse = getHkPayMember(request);
        HashMap<String, Object> resultMap = new HashMap<>();
        Map<String,Object> result = new HashMap<>();
        result.put("pay_info",paymentResponse.getPay_info());
        result.put("token_id",paymentResponse.getToken_id());
        result.put("order_id",request.getOrderNo());
        resultMap.put("data", result);
        resultMap.put("result", "SUCCESS");
        resultMap.put("status", "WECHAT_HK_PAY");
        return resultMap;
    }

    @Override
    public Map<String, Object> purchaseProduct(PurchaseProductRequest purchaseProductRequest, String ip) {
        return null;
    }

    private HkPayPaymentResponse getHkPayMember(BuyMemberRequest request) {
        try {
            HkPayPaymentRequest paymentRequest = new HkPayPaymentRequest();
            //获取商户号 密钥
            String mchId = getSysConfigValue(WeChatConstants.HK_PAY_MCH_ID,request.getMerId());
            String secretKey = getSysConfigValue(WeChatConstants.HK_PAY_SECRET_KEY,request.getMerId());
            String appId = getSysConfigValue(WeChatConstants.HK_PAY_APPID,request.getMerId());

            paymentRequest.setService(WeChatConstants.HK_PAY_JSPAY_SERVICE);
            paymentRequest.setVersion("2.0");
            paymentRequest.setCharset("UTF-8");
            paymentRequest.setSign_type("MD5");
            paymentRequest.setMch_id(mchId);
            paymentRequest.setIs_raw("1");//是否原生态 值為 1：是；值為 0：否；不傳默認是 0
            paymentRequest.setIs_minipg("1");//是否小程式支付 值為 1，表示小程式支付；不傳或值不為 1， 表示公眾帳號內支付
            paymentRequest.setOut_trade_no(request.getOrderNo());
            paymentRequest.setBody("商品描述");
            //用户id 查询openId
            Integer userId = request.getUid();
            LambdaQueryWrapper<UserToken> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserToken::getUid , userId);
            UserToken userToken = userTokenService.getOne(queryWrapper);
            paymentRequest.setSub_openid(userToken.getToken());
            paymentRequest.setSub_appid(appId);
            //TODO 增加用户id等校验
            HkPayAttachVo attachVo = new HkPayAttachVo();
            attachVo.setUserId(userId);
            attachVo.setType("member");
            paymentRequest.setAttach(JSON.toJSONString(attachVo));
            paymentRequest.setTotal_fee(request.getPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
            paymentRequest.setMch_create_ip(request.getClientIp());
            String domain = systemConfigService.getValueByKeyException(WeChatConstants.DOMAIN);
            paymentRequest.setNotify_url(domain + WeChatConstants.PAY_NOTIFY_MEMBER_API_URI_HKPAY);
            paymentRequest.setLimit_credit_pay("0");
//        paymentRequest.setCallback_url("");
//        paymentRequest.setTime_start("");
//        paymentRequest.setTime_expire("");
//        paymentRequest.setGoods_tag("");
            paymentRequest.setNonce_str(getRandomStringByLength(32));
//        paymentRequest.setLimit_credit_pay("0");
            //计算签名
            Map<String, Object> data = CrmebUtil.objectToMap(paymentRequest);
            String sign = WxPayUtil.generateSignature(data, secretKey,"MD5");
            paymentRequest.setSign(sign);
            logger.info("请求香港支付会员参数,param:{} ------- sign:{}", JSONObject.toJSONString(paymentRequest), paymentRequest.getSign());
            String param = XmlUtil.objectToXml(paymentRequest);
            logger.info("请求香港支付会员参数,orderId:{},xml:{}",request.getOrderNo(),param);
            String xml = restTemplateUtil.postXml(WeChatConstants.HK_PAY_API_URL, param);
            logger.info("请求香港支付会员参数响应,orderId:{},xml:{}",request.getOrderNo(),xml);
            if (StringUtils.isBlank(xml)){
                logger.info("香港支付会员接口调用失败");
                throw new CrmebException("香港支付会员接口调用失败");
            }
            //解析xml
            HashMap<String, Object> map = XmlUtil.xmlToMap(xml);
            HkPayPaymentResponse paymentResponse = CrmebUtil.mapToObj(map, HkPayPaymentResponse.class);
            if (!"0".equals(paymentResponse.getStatus())){
                throw new CrmebException(paymentResponse.getMessage());
            }
            if (!"0".equals(paymentResponse.getResult_code())){
                throw new CrmebException(paymentResponse.getErr_msg());
            }
            return paymentResponse;
        }catch (Exception e){
            e.printStackTrace();
            logger.info("请求香港支付会员异常,Exception:{}",e.getMessage());
            throw new CrmebException("香港支付接口调用异常");
        }
    }

    /**
     * 获取退款接口参数
     * @param request
     * @param storeOrder
     * @return
     * @throws Exception
     */
    private HKPayRefundRequest getRefundRequestInfo(StoreOrderRefundRequest request, StoreOrder storeOrder) {
        HKPayRefundRequest refundRequest = new HKPayRefundRequest();
        //获取商户号 密钥
        String mchId = getSysConfigValue(WeChatConstants.HK_PAY_MCH_ID,storeOrder.getMerId());
        String secretKey = getSysConfigValue(WeChatConstants.HK_PAY_SECRET_KEY,storeOrder.getMerId());

        refundRequest.setService(WeChatConstants.HK_PAY_REFUND_SERVICE);
        refundRequest.setMch_id(mchId);
        refundRequest.setOut_trade_no(storeOrder.getOrderId());
        refundRequest.setOut_refund_no(CrmebUtil.getUuid());
        refundRequest.setTotal_fee(storeOrder.getPayPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
        refundRequest.setRefund_fee(request.getAmount().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
        refundRequest.setOp_user_id(mchId);
        refundRequest.setNonce_str(getRandomStringByLength(32));
        //计算签名
        Map<String, Object> data = CrmebUtil.objectToMap(refundRequest);
        String sign = null;
        try {
            sign = WxPayUtil.generateSignature(data, secretKey,"MD5");
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("香港支付退款签名计算异常,Exception:{}",e);
            throw new CrmebException("香港支付退款签名计算异常");
        }
        refundRequest.setSign(sign);
        return refundRequest;
    }

    private String getSysConfigValue(String key, Integer merId) {
        LambdaQueryWrapper<SystemConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SystemConfig::getFormId,merId);
        queryWrapper.eq(SystemConfig::getName,key);
        queryWrapper.last("limit 1");
        SystemConfig systemConfig = systemConfigService.getOne(queryWrapper);
        if (systemConfig == null || StringUtils.isBlank(systemConfig.getValue())){
            throw new CrmebException("退款失败,密钥商户号等信息为空");
        }
        return systemConfig.getValue();
    }


    private static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }


    public static void main(String[] args) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        map.put("amount", "420");
        map.put("api", "order.refundOrder");
        map.put("appId", "bbb23a0b80464a4185a2fb89a306c5c5");
        map.put("v", "1.0");

        map.put("t", "20210512140001");
        map.put("serialNumber", "tk-FD202104211355416986601");
        map.put("userOrderNum", "FD2021042113554169866");
        String sign = CrmebUtil.getOrangeSign(map, "62998c60ec324b2bb2d129ad1fa0a213");
        System.out.println(sign);
        String x = "<xml>\n" +
                "  <service>pay.weixin.jspay</service>\n" +
                "  <mch_id>104550000177</mch_id>\n" +
                "  <is_raw>1</is_raw>\n" +
                "  <out_trade_no>FD2021081616010969572</out_trade_no>\n" +
                "  <body>商品描述</body>\n" +
                "  <sub_openid>oZP1E5THWUTIMbko9awxFiDtJMQw</sub_openid>\n" +
                "  <sub_appid>wx01bc19dc918457cf</sub_appid>\n" +
                "  <attach>商户附加资讯</attach>\n" +
                "  <total_fee>150600</total_fee>\n" +
                "  <mch_create_ip>192.168.31.187</mch_create_ip>\n" +
                "  <notify_url>http://121.4.131.112:8083/api/admin/payment/callback/rechargeNotifyHK</notify_url>\n" +
                "  <nonce_str>krqxysk6j5pwy7rxj62f8g727m2nt7tm</nonce_str>\n" +
                "  <sign>3B8E0D88615FFB7F76D3B8B6D12C0944</sign>\n" +
                "</xml>";
        HashMap<String, Object> stringObjectHashMap = XmlUtil.xmlToMap(x);
        System.out.println(stringObjectHashMap);
    }

    @Override
    public UserRecharge createImgRecharge(BigDecimal price) {
        // TODO Auto-generated method stub
        return null;
    }

}
